/**
 * @date 2006-7-13
 */

package org.nanhill.xmlro;

import static org.nanhill.commons.xml.xpp.XmlPullParser.END_DOCUMENT;
import static org.nanhill.commons.xml.xpp.XmlPullParser.END_TAG;
import static org.nanhill.commons.xml.xpp.XmlPullParser.START_TAG;

import java.io.IOException;
import java.io.Reader;

import org.nanhill.commons.xml.xpp.XmlPullParser;
import org.nanhill.commons.xml.xpp.kxml.io.KXmlParser;

import sun.misc.BASE64Decoder;

/**
 * @author alin [xalinx at gmail dot com]
 * @date 2006-7-13
 */
public abstract class AbstractXmlroInput<E> implements XmlroInput<E> {
	private static final BASE64Decoder base64Decoder = new BASE64Decoder();

	protected boolean isWrapped = false;

	protected E result = null;

	private final XmlPullParser xpp = new KXmlParser();

	protected void unCheckTagName() {
		xpp.unCheckTagName();
	}

	protected AbstractXmlroInput(Reader reader) {
		xpp.setInput(reader);
	}

	public AbstractXmlroInput() {

	}

	public void setReader(Reader reader) {
		xpp.setInput(reader);
	}

	protected Object parse() throws XmlroException {
		assertStartTag();
		String nodeName = xpp.getName();
		Deserializer deserializer = this.getDeserializer(nodeName);
		if (null == deserializer)
			throw new XmlroException("type<" + nodeName
					+ "> has no deserializer!");
		return deserializer.readElement(this);
	}

	protected abstract Deserializer getDeserializer(String nodeName);

	protected byte[] decodeBase64(String v) throws XmlroException {
		try {
			return base64Decoder.decodeBuffer(v);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.xmlro.input.Input#nextTag()
	 */
	public void next() throws XmlroException {
		xpp.next();
	}

	protected String nodeText() {
		return xpp.getText();
	}

	protected String nodeAttributeValue(String attr) {
		return xpp.getAttributeValue(null, attr);
	}

	protected String nodeName() {
		return xpp.getName();
	}

	protected void assertStartTag(String tagName) throws XmlroException {
		xpp.require(START_TAG, null, tagName);
	}

	protected void assertStartTag() throws XmlroException {
		xpp.require(START_TAG, null, null);
	}

	/**
	 * @param string
	 */
	protected void assertEndTag(String tagName) throws XmlroException {
		xpp.require(END_TAG, null, tagName);
	}

	protected boolean isEndTag(String tagName) throws XmlroException {
		return END_TAG == xpp.getEventType() && tagName.equals(nodeName());
	}

	protected boolean isStartTag() throws XmlroException {
		return START_TAG == xpp.getEventType();
	}

	protected boolean isEndDocument() throws XmlroException {
		return END_DOCUMENT == xpp.getEventType();
	}
}
